Class Objectives

This week, we’re going to get used to the environment we’ll use for creating the visualisations for this course. By the end of today, you should be comfortable with the interface, and able to use R, load packages, and do some basic manipulations of dataframes.

What if I get stuck?

It’s OK! Take your orange post-it, and place it on the back of your computer. I’ll come around to help as soon as possible.

If you’ve finished everything, put up your green post-it. I’ll give you some advanced exercises to complete.

Load R Studio using Posit cloud

As last week, we’ll open R using Posit cloud. Use the sidebar to switch to the ‘Information Visualisation and the Humanities’ Workspace, and click on the new assignment, for week 2, called ‘Week 2: Introduction to R’:

You’ll see an existing .Rmd file in the file manager in the bottom right. This is a ‘live’ version of this book chapter. It contains code cells and text. The first part of this practical session simply involves running these cells in the correct order, and looking at the output.

You should now switch to reading this in the .Rmd file in Posit studio. I’ll explain and demonstrate each cell, and then you can run them for yourself.

Following that, you’ll create your own new markdown notebook, and practice some of the techniques we’ve learned- and submit it to Brightspace as a weekly task.

Open the .Rmd file

To begin, click on the .Rmd file. It will open in the reading pane in the top-left. The .Rmd file is an identical copy of this chapter, except you can see the ‘source’, and can change and run the code directly.

If asked to install packages, go ahead and install them. It might take a few moments to complete.

You can switch between two views - again as we saw last week. Either ‘Source’ or ‘Visual’. In the ‘Source’ view, you’ll see the source markdown code used to write the document. The ‘Visual’ view will show the page as it would look when finished, including the images.

As we learned in the previous week, .Rmd files contain ‘regular’ text, as well as code cells - these are shaded boxes with {r} in the left corner. On the right corner, they have a number of icons. Clicking the small green triangle icon will ‘run’ the cell, meaning any code in it will be executed and the output, if any, will be displayed underneath.

Let’s try this here. Click on the green triangle to the right of the shaded code cell below this text:

print("Hello World")

The code (which simply tells R to print the message “Hello World” should run, and the result should appear below.

R code

R code, as most programming languages, involves manipulating data. Data is usually stored as variables and the manipulations are usually done by applying these variables to functions. Often, programmers will write their own functions, but in this course, we’ll exclusively use existing functions, from various packages.

Installing and loading packages

Before we begin, an important part of using R is knowing how to install and load packages. Packages are bundles of pre-made functions, usually with a specific task in mind, such as the sf package for geospatial analysis, or the dplyr package for data wrangling. Many times when using R you will use these packages.

In order to be able to use them, they need to first be installed, and second they need to be loaded.

To install a new package, use the code install.packages() with the package name inside, in quotation marks. For example to install the palmerpenguins package:

install.packages('palmerpenguins')

Loading existing packages

Once you have installed a package, you have to tell R that it should load the functions from the package into the ‘session’, so you can use them. Do this using the command library(). To load the tidyverse package, which we’ll use in this tutorial, run the following cell:

library(tidyverse)

Note that now, the package name does not need to be in quotation marks.

‘Base’ R.

Commands using R without needing any additional packages are often called ‘base’ R. Here are some important ones to know:

You can assign a value to an object using = or <-:


x = 1

y <- 4

Entering the name of a variable in the console and pressing return will return that value in the console. The same will happen if you enter it in a notebook cell (like here below), and run the cell. This is also true of any R object, such as a dataframe, vector, or list.

y

You can do basic calculations with +, -, * and /.

The code below creates a variable x, which is the result of the calculation 1 + 1, a variable y, which is the result of the calculation 4 - 2, and a variable z, which is the result of multiplying x by y. Finally, we print the output of z.

x = 1 + 1

y = 4 - 2

z = x * y

z

You can compare numbers or variables using == (equals), > (greater than), <, (less than) != (not equal to). These return either TRUE or FALSE, which you’ll see if you run this cell:


1 == 1

x > y

x != z

Basic R data structures

It is worth understanding the main types of data that you’ll come across, in your environment window (top-right pane).

A variable is a piece of data stored with a name, which can then be used for various purposes. It’s called a variable because we can change it and re-run the same code. The simplest of these are single elements, such as a number:


x = 1

x

Next is a vector. A vector is a list of elements. A vector is created with the command c(), with each item in the vector placed between the brackets, and followed by a comma. If your vector is a vector of words, the words need to be in inverted commas or quotation marks.

fruit = c("apples", "bananas", "oranges", "apples")
colour = c("green", "yellow", "orange", "red")
amount = c(2,5,10,8)
amount_last_week = c(1,10,3,6)

Next are dataframes. These are the spreadsheet-like objects, with rows and columns, which you’ll use in most analyses.

You can create a dataframe using the data.frame() command. You just need to pass the function each of your vectors, which will become your columns. Don’t worry about the code kableExtra::kbl() for now: it simply prints the table in a way which makes it very clear.

fruit_data = data.frame(fruit, colour, amount,amount_last_week, stringsAsFactors = FALSE)

fruit_data %>% kableExtra::kbl()

We can also use the glimpse() or str() commands to view some basic information on the dataframe (particularly useful with longer data).

glimpse(fruit_data)

Data types

Notice that to the right of the third column, the amount, has <dbl>under it, whereas the other two have <chr>? That’s because R is treating the third as a number and others as a string of characters. It’s often important to know which data type your data is in: you can’t do arithmetic on characters, for example. R has 6 data types:

  • character
  • numeric (real or decimal)
  • integer
  • logical
  • complex
  • Raw

The most commonly-used ones you’ll come across are character, numeric, and logical. logical is data which is either TRUE or FALSE. In R, all the items in a vector are coerced to the same type. So if you try to make a vector with a combination of numbers and strings, the numbers will be converted to strings, as in the example below:

fruit = c("apples", 5, "oranges", 3)

glimpse(fruit)

Tidyverse

Most of the work in this course will use a set of packages developed for R called the ‘tidyverse’. These enhance and improve a large range of R functions with a more intuitive syntax. The Tidyverse is really a ‘family’ of individual packages for sorting, filtering and plotting data frames.

All these functions work in the same way. The first argument is the thing you want to operate on. This is nearly always a data frame. After come other arguments, which are often specific columns, or certain variables you want to do something with.

library(tidyverse)

Here are a couple of the most important ones

select(), pull()

select() allows you to select columns. You can use names or numbers to pick the columns, and you can use a - sign to select everything but a given column.

Using the fruit data frame we created above: We can select just the fruit and colour columns:

select(fruit_data, fruit, colour)

Select everything but the colour column:

select(fruit_data, -colour)

Select the first two columns:

select(fruit_data, 1:2)

group_by(), tally(), summarise()

The next group of functions group things together and count them. Sounds boring but you would be amazed by how much of data science just seems to be doing those two things in various combinations.

group_by() puts rows with the same value in a column of your dataframe into a group. Once they’re in a group, you can count them or summarise them by another variable.

First you need to create a new dataframe with the grouped fruit.

grouped_fruit = group_by(fruit_data, fruit)

Next we use tally(). This counts all the instances of each fruit group.

tally(grouped_fruit)

See? Now the apples are grouped together rather than being two separate rows, and there’s a new column called n, which contains the result of the count.

If we specify that we want to count by something else, we can add that in as a ‘weight’, by adding wt = as an argument in the function.

tally(grouped_fruit, wt = amount)

That counts the amounts of each fruit, ignoring the colour.

filter()

Cartoon of cute fuzzy monsters dressed up as different X-men characters, working together to add a new column to an existing data frame. Stylized title text reads “dplyr::mutate - add columns, keep existing.” Source: https://allisonhorst.com/r-packages-functions
Cartoon of cute fuzzy monsters dressed up as different X-men characters, working together to add a new column to an existing data frame. Stylized title text reads “dplyr::mutate - add columns, keep existing.” Source: https://allisonhorst.com/r-packages-functions

Another quite obviously useful function. This filters the dataframe based on a condition which you set within the function. The first argument is the data to be filtered. The second is a condition (or multiple condition). The function will return every row where that condition is true.

Just red fruit:

filter(fruit_data, colour == 'red')

Just fruit with at least 5 pieces:

filter(fruit_data, amount >=5)

You can also filter with multiple terms by using a vector (as above), and the special command %in%:

filter(fruit_data, colour %in% c('red', 'green'))

mutate()

Mutate creates new columns in your dataframe, based on existing columns or variables.

Cartoon of cute fuzzy monsters dressed up as different X-men characters, working together to add a new column to an existing data frame. Stylized title text reads “dplyr::mutate - add columns, keep existing.” Source: https://allisonhorst.com/r-packages-functions
Cartoon of cute fuzzy monsters dressed up as different X-men characters, working together to add a new column to an existing data frame. Stylized title text reads “dplyr::mutate - add columns, keep existing.” Source: https://allisonhorst.com/r-packages-functions

For example, we can use mutate() to create a new column, adding the results of amount and amount_last_week. Here, we are telling mutate to create a new column called total_amount, and for each row, that column should be the result of summing together the other two columns:

mutate(fruit_data, total_amount = amount + amount_last_week) %>% 
  kableExtra::kbl()

slice_max(), slice_min()

These functions return the top or bottom number of rows, ordered by the data in a particular column.

fruit_data %>% slice_max(order_by = amount, n = 1)

fruit_data %>% slice_min(order_by = amount, n = 1)

These can also be used with group_by(), to give the top rows for each group:

fruit_data %>% group_by(fruit) %>% slice_max(order_by = amount, n  =  1)

Notice it has kept only one row per fruit type, meaning it has kept only the apple row with the highest amount?

sort(), arrange()

Another useful set of functions, often you want to sort things. The function arrange() does this very nicely. You specify the data frame, and the variable you would like to sort by.

arrange(fruit_data, amount)

Sorting is ascending by default, but you can specify descending using desc():

arrange(fruit_data, desc(amount))

If you `sortarrange() by a list of characters, you’ll get alphabetical order:

arrange(fruit_data, fruit)

You can sort by multiple things:

arrange(fruit_data, fruit, desc(amount))

Notice that now red apples are first.

left_join(), inner_join(), anti_join()

Another set of commands we’ll use quite often in this course are the join() ‘family’. Joins are a very powerful but simple way of selecting certain subsets of data, and adding information from multiple tables together.

Let’s make a second table of information giving the delivery day for each fruit type:


fruit_type = c('apples', 'bananas','oranges')
weekday = c('Monday', 'Wednesday', 'Friday')

fruit_days = data.frame(fruit_type, weekday, stringsAsFactors = FALSE)

fruit_days

This can be ‘joined’ to the fruit information, to add the new data on the delivery day, without having to edit the original table (or repeat the information for apples twice). This is done using left_join.

Joins need a common key, a column which allows the join to match the data tables up. It’s important that these are unique (a person’s name makes a bad key by itself, for example, because it’s likely more than one person will share the same name). Usually, we use codes as the join keys. If the columns containing the join keys have different names (as ours do), specify them using the syntax below:


joined_fruit = left_join(fruit_data, fruit_days, by = c("fruit" = "fruit_type"))

joined_fruit

In this new dataframe, the correct weekday is now listed beside the relevant fruit type.

Piping

Another useful feature of the tidyverse is that you can ‘pipe’ commands through a bunch of functions, making it easier to follow the logical order of the code. This means that you can do one operation, and pass the result to another operation. The previous dataframe is passed as the first argument of the next function by using the pipe %>% command. It works like this:

fruit_data %>% 
  filter(colour != 'yellow') %>% # remove any yellow colour fruit
  group_by(fruit) %>% # group the fruit by type
  tally(amount) %>% # count each group
  arrange(desc(n)) # arrange in descending order of the count

That code block, written in prose: “take fruit data, remove any yellow colour fruit, count the fruits by type and amount, and arrange in descending order of the total”

Plotting using ggplot()

The tidyverse includes a plotting library called ggplot2. Almost all of the practical parts of this course will use it, so it’s good to start practising. Don’t worry if you don’t get it at first - we’ll come back to the basics over the next few weeks.

To use it, first type the function ggplot() and specify the dataset you wish to graph using data =. Next, add what is known as a ‘geom’: a function which tells the package to represent the data using a particular geometric form (such as a bar, or a line). These functions begin with the standard form geom_.

Within this geom, you’ll add ‘aesthetics’, which specify to the package which part of the data needs to be mapped to which particular element of the geom. The most common ones include x and y for the x and y axes, color or fill to map colors in your plot to particular data.

Some examples using the fruit data:

Bar chart of different types of fruit (one each of bananas and oranges, two types of apple)

ggplot(data = fruit_data) + geom_col(aes(x = fruit, y = amount))

Counting the total amount of fruit:

ggplot(fruit_data) + geom_col(aes(x = fruit, y = amount))

Charting amounts and fruit colours:

ggplot(data = fruit_data) + geom_bar(aes(x = fruit, weight = amount, fill = colour)) 

Reading in external data

Most of the time, you’ll be working with external data sources. These most commonly come in the form of comma separated values (.csv) or tab separated values (.tsv). The tidyverse commands to read these are read_csv() and read_tsv. You can also use read_delim(), and specify the type of delimited using delim = ',' or delim = '/t. The path to the file is given as a string to the argument file=.

df = read_csv(file = 'top_movie.csv') # Read a .csv file as a network, specify the path to the file here.

df

Notice that each column has a data type beside it, either for text or for numbers. This is important if you want to sort or run calculations on the data.

Advanced: str_¥

Exercises

Now is a chance to practice R skills on your own.

First, create a new markdown notebook, following the instructions from last week.

Next, complete the following exercises. Type the name of the exercise, and then create a separate code cell for each one.

Exercise 0: load the tidyverse library

Load the tidyverse library into your markdown file (for any markdown file, you need to load all the packages you use within it. It doesn’t matter if you have already loaded the packages separately.

Exercise 1: read the file top_movie.csv into R. Give it the name df_movie.

Exercise 2: Create a new version of df_movie, called df_movie_cleaned which:

  • Only includes the years 2000 to 2020.

  • Only contains the year, movie, distributor and total_in_2022_dollars columns.

Exercise 3: summarise the data. Print the following under the cell output:

  • A count of the number of titles in df_movie_cleaned per each distributor.

  • A count of the total box office takings for each distributor.

Exercise 5: Sort the data:

Sort by this latter amount in descending order, and print this result under the cell.

Save and knit the markdown file, submit under ‘weekly tasks’ for week 3.

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMgQ2xhc3MgT2JqZWN0aXZlcwoKVGhpcyB3ZWVrLCB3ZSdyZSBnb2luZyB0byBnZXQgdXNlZCB0byB0aGUgZW52aXJvbm1lbnQgd2UnbGwgdXNlIGZvciBjcmVhdGluZyB0aGUgdmlzdWFsaXNhdGlvbnMgZm9yIHRoaXMgY291cnNlLiBCeSB0aGUgZW5kIG9mIHRvZGF5LCB5b3Ugc2hvdWxkIGJlIGNvbWZvcnRhYmxlIHdpdGggdGhlIGludGVyZmFjZSwgYW5kIGFibGUgdG8gdXNlIFIsIGxvYWQgcGFja2FnZXMsIGFuZCBkbyBzb21lIGJhc2ljIG1hbmlwdWxhdGlvbnMgb2YgZGF0YWZyYW1lcy4KCiMjIyBXaGF0IGlmIEkgZ2V0IHN0dWNrPwoKSXQncyBPSyEgVGFrZSB5b3VyIG9yYW5nZSBwb3N0LWl0LCBhbmQgcGxhY2UgaXQgb24gdGhlIGJhY2sgb2YgeW91ciBjb21wdXRlci4gSSdsbCBjb21lIGFyb3VuZCB0byBoZWxwIGFzIHNvb24gYXMgcG9zc2libGUuCgpJZiB5b3UndmUgZmluaXNoZWQgZXZlcnl0aGluZywgcHV0IHVwIHlvdXIgZ3JlZW4gcG9zdC1pdC4gSSdsbCBnaXZlIHlvdSBzb21lIGFkdmFuY2VkIGV4ZXJjaXNlcyB0byBjb21wbGV0ZS4KCiMjIExvYWQgUiBTdHVkaW8gdXNpbmcgUG9zaXQgY2xvdWQKCkFzIGxhc3Qgd2Vlaywgd2UnbGwgb3BlbiBSIHVzaW5nIFBvc2l0IGNsb3VkLiBVc2UgdGhlIHNpZGViYXIgdG8gc3dpdGNoIHRvIHRoZSAnSW5mb3JtYXRpb24gVmlzdWFsaXNhdGlvbiBhbmQgdGhlIEh1bWFuaXRpZXMnIFdvcmtzcGFjZSwgYW5kIGNsaWNrIG9uIHRoZSBuZXcgYXNzaWdubWVudCwgZm9yIHdlZWsgMiwgY2FsbGVkICdXZWVrIDI6IEludHJvZHVjdGlvbiB0byBSJzoKCiFbXShpbWFnZXMvU2NyZWVuc2hvdCUyMDIwMjMtMDgtMzElMjBhdCUyMDExLjU5LjMxLnBuZyl7d2lkdGg9IjgwMCJ9CgpZb3UnbGwgc2VlIGFuIGV4aXN0aW5nIC5SbWQgZmlsZSBpbiB0aGUgZmlsZSBtYW5hZ2VyIGluIHRoZSBib3R0b20gcmlnaHQuIFRoaXMgaXMgYSAnbGl2ZScgdmVyc2lvbiBvZiB0aGlzIGJvb2sgY2hhcHRlci4gSXQgY29udGFpbnMgY29kZSBjZWxscyBhbmQgdGV4dC4gVGhlIGZpcnN0IHBhcnQgb2YgdGhpcyBwcmFjdGljYWwgc2Vzc2lvbiBzaW1wbHkgaW52b2x2ZXMgcnVubmluZyB0aGVzZSBjZWxscyBpbiB0aGUgY29ycmVjdCBvcmRlciwgYW5kIGxvb2tpbmcgYXQgdGhlIG91dHB1dC4KCllvdSBzaG91bGQgbm93IHN3aXRjaCB0byByZWFkaW5nIHRoaXMgaW4gdGhlIC5SbWQgZmlsZSBpbiBQb3NpdCBzdHVkaW8uIEknbGwgZXhwbGFpbiBhbmQgZGVtb25zdHJhdGUgZWFjaCBjZWxsLCBhbmQgdGhlbiB5b3UgY2FuIHJ1biB0aGVtIGZvciB5b3Vyc2VsZi4KCkZvbGxvd2luZyB0aGF0LCB5b3UnbGwgY3JlYXRlIHlvdXIgb3duIG5ldyBtYXJrZG93biBub3RlYm9vaywgYW5kIHByYWN0aWNlIHNvbWUgb2YgdGhlIHRlY2huaXF1ZXMgd2UndmUgbGVhcm5lZC0gYW5kIHN1Ym1pdCBpdCB0byBCcmlnaHRzcGFjZSBhcyBhIHdlZWtseSB0YXNrLgoKIyMgT3BlbiB0aGUgLlJtZCBmaWxlCgpUbyBiZWdpbiwgY2xpY2sgb24gdGhlIC5SbWQgZmlsZS4gSXQgd2lsbCBvcGVuIGluIHRoZSByZWFkaW5nIHBhbmUgaW4gdGhlIHRvcC1sZWZ0LiBUaGUgLlJtZCBmaWxlIGlzIGFuIGlkZW50aWNhbCBjb3B5IG9mIHRoaXMgY2hhcHRlciwgZXhjZXB0IHlvdSBjYW4gc2VlIHRoZSAnc291cmNlJywgYW5kIGNhbiBjaGFuZ2UgYW5kIHJ1biB0aGUgY29kZSBkaXJlY3RseS4KCklmIGFza2VkIHRvIGluc3RhbGwgcGFja2FnZXMsIGdvIGFoZWFkIGFuZCBpbnN0YWxsIHRoZW0uIEl0IG1pZ2h0IHRha2UgYSBmZXcgbW9tZW50cyB0byBjb21wbGV0ZS4KCllvdSBjYW4gc3dpdGNoIGJldHdlZW4gdHdvIHZpZXdzIC0gYWdhaW4gYXMgd2Ugc2F3IGxhc3Qgd2Vlay4gRWl0aGVyICdTb3VyY2UnIG9yICdWaXN1YWwnLiBJbiB0aGUgJ1NvdXJjZScgdmlldywgeW91J2xsIHNlZSB0aGUgc291cmNlIG1hcmtkb3duIGNvZGUgdXNlZCB0byB3cml0ZSB0aGUgZG9jdW1lbnQuIFRoZSAnVmlzdWFsJyB2aWV3IHdpbGwgc2hvdyB0aGUgcGFnZSBhcyBpdCB3b3VsZCBsb29rIHdoZW4gZmluaXNoZWQsIGluY2x1ZGluZyB0aGUgaW1hZ2VzLgoKQXMgd2UgbGVhcm5lZCBpbiB0aGUgcHJldmlvdXMgd2VlaywgLlJtZCBmaWxlcyBjb250YWluICdyZWd1bGFyJyB0ZXh0LCBhcyB3ZWxsIGFzIGNvZGUgY2VsbHMgLSB0aGVzZSBhcmUgc2hhZGVkIGJveGVzIHdpdGggYHtyfWAgaW4gdGhlIGxlZnQgY29ybmVyLiBPbiB0aGUgcmlnaHQgY29ybmVyLCB0aGV5IGhhdmUgYSBudW1iZXIgb2YgaWNvbnMuIENsaWNraW5nIHRoZSBzbWFsbCBncmVlbiB0cmlhbmdsZSBpY29uIHdpbGwgJ3J1bicgdGhlIGNlbGwsIG1lYW5pbmcgYW55IGNvZGUgaW4gaXQgd2lsbCBiZSBleGVjdXRlZCBhbmQgdGhlIG91dHB1dCwgaWYgYW55LCB3aWxsIGJlIGRpc3BsYXllZCB1bmRlcm5lYXRoLgoKTGV0J3MgdHJ5IHRoaXMgaGVyZS4gQ2xpY2sgb24gdGhlIGdyZWVuIHRyaWFuZ2xlIHRvIHRoZSByaWdodCBvZiB0aGUgc2hhZGVkIGNvZGUgY2VsbCBiZWxvdyB0aGlzIHRleHQ6CgpgYGB7cn0KcHJpbnQoIkhlbGxvIFdvcmxkIikKYGBgCgpUaGUgY29kZSAod2hpY2ggc2ltcGx5IHRlbGxzIFIgdG8gcHJpbnQgdGhlIG1lc3NhZ2UgIkhlbGxvIFdvcmxkIiBzaG91bGQgcnVuLCBhbmQgdGhlIHJlc3VsdCBzaG91bGQgYXBwZWFyIGJlbG93LgoKIyMgUiBjb2RlCgpSIGNvZGUsIGFzIG1vc3QgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2VzLCBpbnZvbHZlcyBtYW5pcHVsYXRpbmcgZGF0YS4gRGF0YSBpcyB1c3VhbGx5IHN0b3JlZCBhcyAqKnZhcmlhYmxlcyoqIGFuZCB0aGUgbWFuaXB1bGF0aW9ucyBhcmUgdXN1YWxseSBkb25lIGJ5IGFwcGx5aW5nIHRoZXNlIHZhcmlhYmxlcyB0byAqKmZ1bmN0aW9ucy4qKiBPZnRlbiwgcHJvZ3JhbW1lcnMgd2lsbCB3cml0ZSB0aGVpciBvd24gZnVuY3Rpb25zLCBidXQgaW4gdGhpcyBjb3Vyc2UsIHdlJ2xsIGV4Y2x1c2l2ZWx5IHVzZSBleGlzdGluZyBmdW5jdGlvbnMsIGZyb20gdmFyaW91cyBwYWNrYWdlcy4KCiMjIEluc3RhbGxpbmcgYW5kIGxvYWRpbmcgcGFja2FnZXMKCkJlZm9yZSB3ZSBiZWdpbiwgYW4gaW1wb3J0YW50IHBhcnQgb2YgdXNpbmcgUiBpcyBrbm93aW5nIGhvdyB0byBpbnN0YWxsIGFuZCBsb2FkIHBhY2thZ2VzLiBQYWNrYWdlcyBhcmUgYnVuZGxlcyBvZiBwcmUtbWFkZSBmdW5jdGlvbnMsIHVzdWFsbHkgd2l0aCBhIHNwZWNpZmljIHRhc2sgaW4gbWluZCwgc3VjaCBhcyB0aGUgYHNmYCBwYWNrYWdlIGZvciBnZW9zcGF0aWFsIGFuYWx5c2lzLCBvciB0aGUgYGRwbHlyYCBwYWNrYWdlIGZvciBkYXRhIHdyYW5nbGluZy4gTWFueSB0aW1lcyB3aGVuIHVzaW5nIFIgeW91IHdpbGwgdXNlIHRoZXNlIHBhY2thZ2VzLgoKSW4gb3JkZXIgdG8gYmUgYWJsZSB0byB1c2UgdGhlbSwgdGhleSBuZWVkIHRvIGZpcnN0IGJlIGluc3RhbGxlZCwgYW5kIHNlY29uZCB0aGV5IG5lZWQgdG8gYmUgbG9hZGVkLgoKVG8gaW5zdGFsbCBhIG5ldyBwYWNrYWdlLCB1c2UgdGhlIGNvZGUgYGluc3RhbGwucGFja2FnZXMoKWAgd2l0aCB0aGUgcGFja2FnZSBuYW1lIGluc2lkZSwgaW4gcXVvdGF0aW9uIG1hcmtzLiBGb3IgZXhhbXBsZSB0byBpbnN0YWxsIHRoZSBgcGFsbWVycGVuZ3VpbnNgIHBhY2thZ2U6CgpgYGB7cn0KI3wgZXZhbDogZmFsc2UKCgoKaW5zdGFsbC5wYWNrYWdlcygncGFsbWVycGVuZ3VpbnMnKQoKYGBgCgojIyBMb2FkaW5nIGV4aXN0aW5nIHBhY2thZ2VzCgpPbmNlIHlvdSBoYXZlIGluc3RhbGxlZCBhIHBhY2thZ2UsIHlvdSBoYXZlIHRvIHRlbGwgUiB0aGF0IGl0IHNob3VsZCBsb2FkIHRoZSBmdW5jdGlvbnMgZnJvbSB0aGUgcGFja2FnZSBpbnRvIHRoZSAnc2Vzc2lvbicsIHNvIHlvdSBjYW4gdXNlIHRoZW0uIERvIHRoaXMgdXNpbmcgdGhlIGNvbW1hbmQgYGxpYnJhcnkoKWAuIFRvIGxvYWQgdGhlIGB0aWR5dmVyc2VgIHBhY2thZ2UsIHdoaWNoIHdlJ2xsIHVzZSBpbiB0aGlzIHR1dG9yaWFsLCBydW4gdGhlIGZvbGxvd2luZyBjZWxsOgoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpgYGAKCk5vdGUgdGhhdCBub3csIHRoZSBwYWNrYWdlIG5hbWUgZG9lcyBub3QgbmVlZCB0byBiZSBpbiBxdW90YXRpb24gbWFya3MuCgojIyMgJ0Jhc2UnIFIuCgpDb21tYW5kcyB1c2luZyBSIHdpdGhvdXQgbmVlZGluZyBhbnkgYWRkaXRpb25hbCBwYWNrYWdlcyBhcmUgb2Z0ZW4gY2FsbGVkICdiYXNlJyBSLiBIZXJlIGFyZSBzb21lIGltcG9ydGFudCBvbmVzIHRvIGtub3c6CgpZb3UgY2FuIGFzc2lnbiBhIHZhbHVlIHRvIGFuIG9iamVjdCB1c2luZyBgPWAgb3IgYDwtYDoKCmBgYHtyfQoKeCA9IDEKCnkgPC0gNAoKYGBgCgpFbnRlcmluZyB0aGUgbmFtZSBvZiBhIHZhcmlhYmxlIGluIHRoZSBjb25zb2xlIGFuZCBwcmVzc2luZyByZXR1cm4gd2lsbCByZXR1cm4gdGhhdCB2YWx1ZSBpbiB0aGUgY29uc29sZS4gVGhlIHNhbWUgd2lsbCBoYXBwZW4gaWYgeW91IGVudGVyIGl0IGluIGEgbm90ZWJvb2sgY2VsbCAobGlrZSBoZXJlIGJlbG93KSwgYW5kIHJ1biB0aGUgY2VsbC4gVGhpcyBpcyBhbHNvIHRydWUgb2YgYW55IFIgb2JqZWN0LCBzdWNoIGFzIGEgZGF0YWZyYW1lLCB2ZWN0b3IsIG9yIGxpc3QuCgpgYGB7cn0KeQpgYGAKCllvdSBjYW4gZG8gYmFzaWMgY2FsY3VsYXRpb25zIHdpdGggYCtgLCBgLWAsIGAqYCBhbmQgYC9gLgoKVGhlIGNvZGUgYmVsb3cgY3JlYXRlcyBhIHZhcmlhYmxlIGB4YCwgd2hpY2ggaXMgdGhlIHJlc3VsdCBvZiB0aGUgY2FsY3VsYXRpb24gYDEgKyAxYCwgYSB2YXJpYWJsZSB5LCB3aGljaCBpcyB0aGUgcmVzdWx0IG9mIHRoZSBjYWxjdWxhdGlvbiBgNCAtIDJgLCBhbmQgYSB2YXJpYWJsZSBgemAsIHdoaWNoIGlzIHRoZSByZXN1bHQgb2YgbXVsdGlwbHlpbmcgYHhgIGJ5IGB5YC4gRmluYWxseSwgd2UgcHJpbnQgdGhlIG91dHB1dCBvZiBgemAuCgpgYGB7cn0KeCA9IDEgKyAxCgp5ID0gNCAtIDIKCnogPSB4ICogeQoKegpgYGAKCllvdSBjYW4gY29tcGFyZSBudW1iZXJzIG9yIHZhcmlhYmxlcyB1c2luZyBgPT1gIChlcXVhbHMpLCBgPmAgKGdyZWF0ZXIgdGhhbiksIGA8YCwgKGxlc3MgdGhhbikgYCE9YCAobm90IGVxdWFsIHRvKS4gVGhlc2UgcmV0dXJuIGVpdGhlciBgVFJVRWAgb3IgYEZBTFNFYCwgd2hpY2ggeW91J2xsIHNlZSBpZiB5b3UgcnVuIHRoaXMgY2VsbDoKCmBgYHtyfQoKMSA9PSAxCgp4ID4geQoKeCAhPSB6CgpgYGAKCiMjIyBCYXNpYyBSIGRhdGEgc3RydWN0dXJlcwoKSXQgaXMgd29ydGggdW5kZXJzdGFuZGluZyB0aGUgbWFpbiB0eXBlcyBvZiBkYXRhIHRoYXQgeW91J2xsIGNvbWUgYWNyb3NzLCBpbiB5b3VyIGVudmlyb25tZW50IHdpbmRvdyAodG9wLXJpZ2h0IHBhbmUpLgoKQSAqKnZhcmlhYmxlKiogaXMgYSBwaWVjZSBvZiBkYXRhIHN0b3JlZCB3aXRoIGEgbmFtZSwgd2hpY2ggY2FuIHRoZW4gYmUgdXNlZCBmb3IgdmFyaW91cyBwdXJwb3Nlcy4gSXQncyBjYWxsZWQgYSB2YXJpYWJsZSBiZWNhdXNlIHdlIGNhbiBjaGFuZ2UgaXQgYW5kIHJlLXJ1biB0aGUgc2FtZSBjb2RlLiBUaGUgc2ltcGxlc3Qgb2YgdGhlc2UgYXJlIHNpbmdsZSAqKmVsZW1lbnRzKiosIHN1Y2ggYXMgYSBudW1iZXI6CgpgYGB7cn0KCnggPSAxCgp4CmBgYAoKTmV4dCBpcyBhIHZlY3Rvci4gQSB2ZWN0b3IgaXMgYSBsaXN0IG9mICoqZWxlbWVudHMqKi4gQSB2ZWN0b3IgaXMgY3JlYXRlZCB3aXRoIHRoZSBjb21tYW5kIGBjKClgLCB3aXRoIGVhY2ggaXRlbSBpbiB0aGUgdmVjdG9yIHBsYWNlZCBiZXR3ZWVuIHRoZSBicmFja2V0cywgYW5kIGZvbGxvd2VkIGJ5IGEgY29tbWEuIElmIHlvdXIgdmVjdG9yIGlzIGEgdmVjdG9yIG9mIHdvcmRzLCB0aGUgd29yZHMgbmVlZCB0byBiZSBpbiBpbnZlcnRlZCBjb21tYXMgb3IgcXVvdGF0aW9uIG1hcmtzLgoKYGBge3J9CmZydWl0ID0gYygiYXBwbGVzIiwgImJhbmFuYXMiLCAib3JhbmdlcyIsICJhcHBsZXMiKQpjb2xvdXIgPSBjKCJncmVlbiIsICJ5ZWxsb3ciLCAib3JhbmdlIiwgInJlZCIpCmFtb3VudCA9IGMoMiw1LDEwLDgpCmFtb3VudF9sYXN0X3dlZWsgPSBjKDEsMTAsMyw2KQpgYGAKCk5leHQgYXJlIGRhdGFmcmFtZXMuIFRoZXNlIGFyZSB0aGUgc3ByZWFkc2hlZXQtbGlrZSBvYmplY3RzLCB3aXRoIHJvd3MgYW5kIGNvbHVtbnMsIHdoaWNoIHlvdSdsbCB1c2UgaW4gbW9zdCBhbmFseXNlcy4KCllvdSBjYW4gY3JlYXRlIGEgZGF0YWZyYW1lIHVzaW5nIHRoZSBgZGF0YS5mcmFtZSgpYCBjb21tYW5kLiBZb3UganVzdCBuZWVkIHRvIHBhc3MgdGhlIGZ1bmN0aW9uIGVhY2ggb2YgeW91ciB2ZWN0b3JzLCB3aGljaCB3aWxsIGJlY29tZSB5b3VyIGNvbHVtbnMuIERvbid0IHdvcnJ5IGFib3V0IHRoZSBjb2RlIGBrYWJsZUV4dHJhOjprYmwoKWAgZm9yIG5vdzogaXQgc2ltcGx5IHByaW50cyB0aGUgdGFibGUgaW4gYSB3YXkgd2hpY2ggbWFrZXMgaXQgdmVyeSBjbGVhci4KCmBgYHtyfQpmcnVpdF9kYXRhID0gZGF0YS5mcmFtZShmcnVpdCwgY29sb3VyLCBhbW91bnQsYW1vdW50X2xhc3Rfd2Vlaywgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQoKZnJ1aXRfZGF0YSAlPiUga2FibGVFeHRyYTo6a2JsKCkKYGBgCgpXZSBjYW4gYWxzbyB1c2UgdGhlIGBnbGltcHNlKClgIG9yIGBzdHIoKWAgY29tbWFuZHMgdG8gdmlldyBzb21lIGJhc2ljIGluZm9ybWF0aW9uIG9uIHRoZSBkYXRhZnJhbWUgKHBhcnRpY3VsYXJseSB1c2VmdWwgd2l0aCBsb25nZXIgZGF0YSkuCgpgYGB7cn0KZ2xpbXBzZShmcnVpdF9kYXRhKQpgYGAKCiMjIyBEYXRhIHR5cGVzCgpOb3RpY2UgdGhhdCB0byB0aGUgcmlnaHQgb2YgdGhlIHRoaXJkIGNvbHVtbiwgdGhlIGFtb3VudCwgaGFzIGA8ZGJsPmB1bmRlciBpdCwgd2hlcmVhcyB0aGUgb3RoZXIgdHdvIGhhdmUgYDxjaHI+YD8gVGhhdCdzIGJlY2F1c2UgUiBpcyB0cmVhdGluZyB0aGUgdGhpcmQgYXMgYSBudW1iZXIgYW5kIG90aGVycyBhcyBhIHN0cmluZyBvZiBjaGFyYWN0ZXJzLiBJdCdzIG9mdGVuIGltcG9ydGFudCB0byBrbm93IHdoaWNoIGRhdGEgdHlwZSB5b3VyIGRhdGEgaXMgaW46IHlvdSBjYW4ndCBkbyBhcml0aG1ldGljIG9uIGNoYXJhY3RlcnMsIGZvciBleGFtcGxlLiBSIGhhcyA2IGRhdGEgdHlwZXM6CgotICAgY2hhcmFjdGVyCi0gICBudW1lcmljIChyZWFsIG9yIGRlY2ltYWwpCi0gICBpbnRlZ2VyCi0gICBsb2dpY2FsCi0gICBjb21wbGV4Ci0gICBSYXcKClRoZSBtb3N0IGNvbW1vbmx5LXVzZWQgb25lcyB5b3UnbGwgY29tZSBhY3Jvc3MgYXJlIGBjaGFyYWN0ZXJgLCBgbnVtZXJpY2AsIGFuZCBgbG9naWNhbGAuIGBsb2dpY2FsYCBpcyBkYXRhIHdoaWNoIGlzIGVpdGhlciBgVFJVRWAgb3IgYEZBTFNFYC4gSW4gUiwgYWxsIHRoZSBpdGVtcyBpbiBhIHZlY3RvciBhcmUgKmNvZXJjZWQqIHRvIHRoZSBzYW1lIHR5cGUuIFNvIGlmIHlvdSB0cnkgdG8gbWFrZSBhIHZlY3RvciB3aXRoIGEgY29tYmluYXRpb24gb2YgbnVtYmVycyBhbmQgc3RyaW5ncywgdGhlIG51bWJlcnMgd2lsbCBiZSBjb252ZXJ0ZWQgdG8gc3RyaW5ncywgYXMgaW4gdGhlIGV4YW1wbGUgYmVsb3c6CgpgYGB7cn0KZnJ1aXQgPSBjKCJhcHBsZXMiLCA1LCAib3JhbmdlcyIsIDMpCgpnbGltcHNlKGZydWl0KQpgYGAKCiMjIFRpZHl2ZXJzZQoKTW9zdCBvZiB0aGUgd29yayBpbiB0aGlzIGNvdXJzZSB3aWxsIHVzZSBhIHNldCBvZiBwYWNrYWdlcyBkZXZlbG9wZWQgZm9yIFIgY2FsbGVkIHRoZSAndGlkeXZlcnNlJy4gVGhlc2UgZW5oYW5jZSBhbmQgaW1wcm92ZSBhIGxhcmdlIHJhbmdlIG9mIFIgZnVuY3Rpb25zIHdpdGggYSBtb3JlIGludHVpdGl2ZSBzeW50YXguIFRoZSBUaWR5dmVyc2UgaXMgcmVhbGx5IGEgJ2ZhbWlseScgb2YgaW5kaXZpZHVhbCBwYWNrYWdlcyBmb3Igc29ydGluZywgZmlsdGVyaW5nIGFuZCBwbG90dGluZyBkYXRhIGZyYW1lcy4KCkFsbCB0aGVzZSBmdW5jdGlvbnMgd29yayBpbiB0aGUgc2FtZSB3YXkuIFRoZSBmaXJzdCBhcmd1bWVudCBpcyB0aGUgdGhpbmcgeW91IHdhbnQgdG8gb3BlcmF0ZSBvbi4gVGhpcyBpcyBuZWFybHkgYWx3YXlzIGEgZGF0YSBmcmFtZS4gQWZ0ZXIgY29tZSBvdGhlciBhcmd1bWVudHMsIHdoaWNoIGFyZSBvZnRlbiBzcGVjaWZpYyBjb2x1bW5zLCBvciBjZXJ0YWluIHZhcmlhYmxlcyB5b3Ugd2FudCB0byBkbyBzb21ldGhpbmcgd2l0aC4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpgYGAKCkhlcmUgYXJlIGEgY291cGxlIG9mIHRoZSBtb3N0IGltcG9ydGFudCBvbmVzCgojIyMgc2VsZWN0KCksIHB1bGwoKQoKYHNlbGVjdCgpYCBhbGxvd3MgeW91IHRvIHNlbGVjdCBjb2x1bW5zLiBZb3UgY2FuIHVzZSBuYW1lcyBvciBudW1iZXJzIHRvIHBpY2sgdGhlIGNvbHVtbnMsIGFuZCB5b3UgY2FuIHVzZSBhIGAtYCBzaWduIHRvIHNlbGVjdCBldmVyeXRoaW5nICpidXQqIGEgZ2l2ZW4gY29sdW1uLgoKVXNpbmcgdGhlIGZydWl0IGRhdGEgZnJhbWUgd2UgY3JlYXRlZCBhYm92ZTogV2UgY2FuIHNlbGVjdCBqdXN0IHRoZSBmcnVpdCBhbmQgY29sb3VyIGNvbHVtbnM6CgpgYGB7cn0Kc2VsZWN0KGZydWl0X2RhdGEsIGZydWl0LCBjb2xvdXIpCmBgYAoKU2VsZWN0IGV2ZXJ5dGhpbmcgYnV0IHRoZSBjb2xvdXIgY29sdW1uOgoKYGBge3J9CnNlbGVjdChmcnVpdF9kYXRhLCAtY29sb3VyKQpgYGAKClNlbGVjdCB0aGUgZmlyc3QgdHdvIGNvbHVtbnM6CgpgYGB7cn0Kc2VsZWN0KGZydWl0X2RhdGEsIDE6MikKYGBgCgojIyMgZ3JvdXBfYnkoKSwgdGFsbHkoKSwgc3VtbWFyaXNlKCkKClRoZSBuZXh0IGdyb3VwIG9mIGZ1bmN0aW9ucyBncm91cCB0aGluZ3MgdG9nZXRoZXIgYW5kIGNvdW50IHRoZW0uIFNvdW5kcyBib3JpbmcgYnV0IHlvdSB3b3VsZCBiZSBhbWF6ZWQgYnkgaG93IG11Y2ggb2YgZGF0YSBzY2llbmNlIGp1c3Qgc2VlbXMgdG8gYmUgZG9pbmcgdGhvc2UgdHdvIHRoaW5ncyBpbiB2YXJpb3VzIGNvbWJpbmF0aW9ucy4KCmBncm91cF9ieSgpYCBwdXRzIHJvd3Mgd2l0aCB0aGUgc2FtZSB2YWx1ZSBpbiBhIGNvbHVtbiBvZiB5b3VyIGRhdGFmcmFtZSBpbnRvIGEgZ3JvdXAuIE9uY2UgdGhleSdyZSBpbiBhIGdyb3VwLCB5b3UgY2FuIGNvdW50IHRoZW0gb3Igc3VtbWFyaXNlIHRoZW0gYnkgYW5vdGhlciB2YXJpYWJsZS4KCkZpcnN0IHlvdSBuZWVkIHRvIGNyZWF0ZSBhIG5ldyBkYXRhZnJhbWUgd2l0aCB0aGUgZ3JvdXBlZCBmcnVpdC4KCmBgYHtyfQpncm91cGVkX2ZydWl0ID0gZ3JvdXBfYnkoZnJ1aXRfZGF0YSwgZnJ1aXQpCmBgYAoKTmV4dCB3ZSB1c2UgYHRhbGx5KClgLiBUaGlzIGNvdW50cyBhbGwgdGhlIGluc3RhbmNlcyBvZiBlYWNoIGZydWl0IGdyb3VwLgoKYGBge3J9CnRhbGx5KGdyb3VwZWRfZnJ1aXQpCmBgYAoKU2VlPyBOb3cgdGhlIGFwcGxlcyBhcmUgZ3JvdXBlZCB0b2dldGhlciByYXRoZXIgdGhhbiBiZWluZyB0d28gc2VwYXJhdGUgcm93cywgYW5kIHRoZXJlJ3MgYSBuZXcgY29sdW1uIGNhbGxlZCBgbmAsIHdoaWNoIGNvbnRhaW5zIHRoZSByZXN1bHQgb2YgdGhlIGNvdW50LgoKSWYgd2Ugc3BlY2lmeSB0aGF0IHdlIHdhbnQgdG8gY291bnQgYnkgc29tZXRoaW5nIGVsc2UsIHdlIGNhbiBhZGQgdGhhdCBpbiBhcyBhICd3ZWlnaHQnLCBieSBhZGRpbmcgYHd0ID1gIGFzIGFuIGFyZ3VtZW50IGluIHRoZSBmdW5jdGlvbi4KCmBgYHtyfQp0YWxseShncm91cGVkX2ZydWl0LCB3dCA9IGFtb3VudCkKYGBgCgpUaGF0IGNvdW50cyB0aGUgYW1vdW50cyBvZiBlYWNoIGZydWl0LCBpZ25vcmluZyB0aGUgY29sb3VyLgoKIyMjIGZpbHRlcigpCgohW0NhcnRvb24gb2YgY3V0ZSBmdXp6eSBtb25zdGVycyBkcmVzc2VkIHVwIGFzIGRpZmZlcmVudCBYLW1lbiBjaGFyYWN0ZXJzLCB3b3JraW5nIHRvZ2V0aGVyIHRvIGFkZCBhIG5ldyBjb2x1bW4gdG8gYW4gZXhpc3RpbmcgZGF0YSBmcmFtZS4gU3R5bGl6ZWQgdGl0bGUgdGV4dCByZWFkcyAiZHBseXI6Om11dGF0ZSAtIGFkZCBjb2x1bW5zLCBrZWVwIGV4aXN0aW5nLiIgU291cmNlOiBodHRwczovL2FsbGlzb25ob3JzdC5jb20vci1wYWNrYWdlcy1mdW5jdGlvbnNdKGltYWdlcy9jYjhkOWM1MC1mNDhlLTRjNmQtYTViMy0xZDMwY2UwYmUyYWQucG5nKXt3aWR0aD0iNjAwIn0KCkFub3RoZXIgcXVpdGUgb2J2aW91c2x5IHVzZWZ1bCBmdW5jdGlvbi4gVGhpcyBmaWx0ZXJzIHRoZSBkYXRhZnJhbWUgYmFzZWQgb24gYSBjb25kaXRpb24gd2hpY2ggeW91IHNldCB3aXRoaW4gdGhlIGZ1bmN0aW9uLiBUaGUgZmlyc3QgYXJndW1lbnQgaXMgdGhlIGRhdGEgdG8gYmUgZmlsdGVyZWQuIFRoZSBzZWNvbmQgaXMgYSBjb25kaXRpb24gKG9yIG11bHRpcGxlIGNvbmRpdGlvbikuIFRoZSBmdW5jdGlvbiB3aWxsIHJldHVybiBldmVyeSByb3cgd2hlcmUgdGhhdCBjb25kaXRpb24gaXMgdHJ1ZS4KCkp1c3QgcmVkIGZydWl0OgoKYGBge3J9CmZpbHRlcihmcnVpdF9kYXRhLCBjb2xvdXIgPT0gJ3JlZCcpCmBgYAoKSnVzdCBmcnVpdCB3aXRoIGF0IGxlYXN0IDUgcGllY2VzOgoKYGBge3J9CmZpbHRlcihmcnVpdF9kYXRhLCBhbW91bnQgPj01KQpgYGAKCllvdSBjYW4gYWxzbyBmaWx0ZXIgd2l0aCBtdWx0aXBsZSB0ZXJtcyBieSB1c2luZyBhIHZlY3RvciAoYXMgYWJvdmUpLCBhbmQgdGhlIHNwZWNpYWwgY29tbWFuZCBgJWluJWA6CgpgYGB7cn0KZmlsdGVyKGZydWl0X2RhdGEsIGNvbG91ciAlaW4lIGMoJ3JlZCcsICdncmVlbicpKQpgYGAKCiMjIyBtdXRhdGUoKQoKTXV0YXRlIGNyZWF0ZXMgbmV3IGNvbHVtbnMgaW4geW91ciBkYXRhZnJhbWUsIGJhc2VkIG9uIGV4aXN0aW5nIGNvbHVtbnMgb3IgdmFyaWFibGVzLgoKIVtDYXJ0b29uIG9mIGN1dGUgZnV6enkgbW9uc3RlcnMgZHJlc3NlZCB1cCBhcyBkaWZmZXJlbnQgWC1tZW4gY2hhcmFjdGVycywgd29ya2luZyB0b2dldGhlciB0byBhZGQgYSBuZXcgY29sdW1uIHRvIGFuIGV4aXN0aW5nIGRhdGEgZnJhbWUuIFN0eWxpemVkIHRpdGxlIHRleHQgcmVhZHMgImRwbHlyOjptdXRhdGUgLSBhZGQgY29sdW1ucywga2VlcCBleGlzdGluZy4iIFNvdXJjZTogaHR0cHM6Ly9hbGxpc29uaG9yc3QuY29tL3ItcGFja2FnZXMtZnVuY3Rpb25zXShpbWFnZXMvYmQ0YWUyNjQtYWU1MS00ZDE4LWJkNjAtN2EwNThhYjQyZmJhLnBuZyl7d2lkdGg9IjYwMCJ9CgpGb3IgZXhhbXBsZSwgd2UgY2FuIHVzZSBgbXV0YXRlKClgIHRvIGNyZWF0ZSBhIG5ldyBjb2x1bW4sIGFkZGluZyB0aGUgcmVzdWx0cyBvZiBgYW1vdW50YCBhbmQgYGFtb3VudF9sYXN0X3dlZWtgLiBIZXJlLCB3ZSBhcmUgdGVsbGluZyBtdXRhdGUgdG8gY3JlYXRlIGEgbmV3IGNvbHVtbiBjYWxsZWQgYHRvdGFsX2Ftb3VudGAsIGFuZCBmb3IgZWFjaCByb3csIHRoYXQgY29sdW1uIHNob3VsZCBiZSB0aGUgcmVzdWx0IG9mIHN1bW1pbmcgdG9nZXRoZXIgdGhlIG90aGVyIHR3byBjb2x1bW5zOgoKYGBge3J9Cm11dGF0ZShmcnVpdF9kYXRhLCB0b3RhbF9hbW91bnQgPSBhbW91bnQgKyBhbW91bnRfbGFzdF93ZWVrKSAlPiUgCiAga2FibGVFeHRyYTo6a2JsKCkKYGBgCgojIyMgc2xpY2VfbWF4KCksIHNsaWNlX21pbigpCgpUaGVzZSBmdW5jdGlvbnMgcmV0dXJuIHRoZSB0b3Agb3IgYm90dG9tIG51bWJlciBvZiByb3dzLCBvcmRlcmVkIGJ5IHRoZSBkYXRhIGluIGEgcGFydGljdWxhciBjb2x1bW4uCgpgYGB7cn0KZnJ1aXRfZGF0YSAlPiUgc2xpY2VfbWF4KG9yZGVyX2J5ID0gYW1vdW50LCBuID0gMSkKCmZydWl0X2RhdGEgJT4lIHNsaWNlX21pbihvcmRlcl9ieSA9IGFtb3VudCwgbiA9IDEpCmBgYAoKVGhlc2UgY2FuIGFsc28gYmUgdXNlZCB3aXRoIGBncm91cF9ieSgpYCwgdG8gZ2l2ZSB0aGUgdG9wIHJvd3MgZm9yIGVhY2ggZ3JvdXA6CgpgYGB7cn0KZnJ1aXRfZGF0YSAlPiUgZ3JvdXBfYnkoZnJ1aXQpICU+JSBzbGljZV9tYXgob3JkZXJfYnkgPSBhbW91bnQsIG4gID0gIDEpCmBgYAoKTm90aWNlIGl0IGhhcyBrZXB0IG9ubHkgb25lIHJvdyBwZXIgZnJ1aXQgdHlwZSwgbWVhbmluZyBpdCBoYXMga2VwdCBvbmx5IHRoZSBhcHBsZSByb3cgd2l0aCB0aGUgaGlnaGVzdCBhbW91bnQ/CgojIyMgc29ydCgpLCBhcnJhbmdlKCkKCkFub3RoZXIgdXNlZnVsIHNldCBvZiBmdW5jdGlvbnMsIG9mdGVuIHlvdSB3YW50IHRvIHNvcnQgdGhpbmdzLiBUaGUgZnVuY3Rpb24gYGFycmFuZ2UoKWAgZG9lcyB0aGlzIHZlcnkgbmljZWx5LiBZb3Ugc3BlY2lmeSB0aGUgZGF0YSBmcmFtZSwgYW5kIHRoZSB2YXJpYWJsZSB5b3Ugd291bGQgbGlrZSB0byBzb3J0IGJ5LgoKYGBge3J9CmFycmFuZ2UoZnJ1aXRfZGF0YSwgYW1vdW50KQpgYGAKClNvcnRpbmcgaXMgYXNjZW5kaW5nIGJ5IGRlZmF1bHQsIGJ1dCB5b3UgY2FuIHNwZWNpZnkgZGVzY2VuZGluZyB1c2luZyBgZGVzYygpYDoKCmBgYHtyfQphcnJhbmdlKGZydWl0X2RhdGEsIGRlc2MoYW1vdW50KSkKYGBgCgpJZiB5b3UgXGBzb3J0YGFycmFuZ2UoKWAgYnkgYSBsaXN0IG9mIGNoYXJhY3RlcnMsIHlvdSdsbCBnZXQgYWxwaGFiZXRpY2FsIG9yZGVyOgoKYGBge3J9CmFycmFuZ2UoZnJ1aXRfZGF0YSwgZnJ1aXQpCmBgYAoKWW91IGNhbiBzb3J0IGJ5IG11bHRpcGxlIHRoaW5nczoKCmBgYHtyfQphcnJhbmdlKGZydWl0X2RhdGEsIGZydWl0LCBkZXNjKGFtb3VudCkpCmBgYAoKTm90aWNlIHRoYXQgbm93IHJlZCBhcHBsZXMgYXJlIGZpcnN0LgoKIyMjIGxlZnRfam9pbigpLCBpbm5lcl9qb2luKCksIGFudGlfam9pbigpCgpBbm90aGVyIHNldCBvZiBjb21tYW5kcyB3ZSdsbCB1c2UgcXVpdGUgb2Z0ZW4gaW4gdGhpcyBjb3Vyc2UgYXJlIHRoZSBgam9pbigpYCAnZmFtaWx5Jy4gSm9pbnMgYXJlIGEgdmVyeSBwb3dlcmZ1bCBidXQgc2ltcGxlIHdheSBvZiBzZWxlY3RpbmcgY2VydGFpbiBzdWJzZXRzIG9mIGRhdGEsIGFuZCBhZGRpbmcgaW5mb3JtYXRpb24gZnJvbSBtdWx0aXBsZSB0YWJsZXMgdG9nZXRoZXIuCgpMZXQncyBtYWtlIGEgc2Vjb25kIHRhYmxlIG9mIGluZm9ybWF0aW9uIGdpdmluZyB0aGUgZGVsaXZlcnkgZGF5IGZvciBlYWNoIGZydWl0IHR5cGU6CgpgYGB7cn0KCmZydWl0X3R5cGUgPSBjKCdhcHBsZXMnLCAnYmFuYW5hcycsJ29yYW5nZXMnKQp3ZWVrZGF5ID0gYygnTW9uZGF5JywgJ1dlZG5lc2RheScsICdGcmlkYXknKQoKZnJ1aXRfZGF5cyA9IGRhdGEuZnJhbWUoZnJ1aXRfdHlwZSwgd2Vla2RheSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQoKZnJ1aXRfZGF5cwoKYGBgCgpUaGlzIGNhbiBiZSAnam9pbmVkJyB0byB0aGUgZnJ1aXQgaW5mb3JtYXRpb24sIHRvIGFkZCB0aGUgbmV3IGRhdGEgb24gdGhlIGRlbGl2ZXJ5IGRheSwgd2l0aG91dCBoYXZpbmcgdG8gZWRpdCB0aGUgb3JpZ2luYWwgdGFibGUgKG9yIHJlcGVhdCB0aGUgaW5mb3JtYXRpb24gZm9yIGFwcGxlcyB0d2ljZSkuIFRoaXMgaXMgZG9uZSB1c2luZyBgbGVmdF9qb2luYC4KCkpvaW5zIG5lZWQgYSBjb21tb24gYGtleWAsIGEgY29sdW1uIHdoaWNoIGFsbG93cyB0aGUgam9pbiB0byBtYXRjaCB0aGUgZGF0YSB0YWJsZXMgdXAuIEl0J3MgaW1wb3J0YW50IHRoYXQgdGhlc2UgYXJlIHVuaXF1ZSAoYSBwZXJzb24ncyBuYW1lIG1ha2VzIGEgYmFkIGtleSBieSBpdHNlbGYsIGZvciBleGFtcGxlLCBiZWNhdXNlIGl0J3MgbGlrZWx5IG1vcmUgdGhhbiBvbmUgcGVyc29uIHdpbGwgc2hhcmUgdGhlIHNhbWUgbmFtZSkuIFVzdWFsbHksIHdlIHVzZSBjb2RlcyBhcyB0aGUgam9pbiBrZXlzLiBJZiB0aGUgY29sdW1ucyBjb250YWluaW5nIHRoZSBqb2luIGtleXMgaGF2ZSBkaWZmZXJlbnQgbmFtZXMgKGFzIG91cnMgZG8pLCBzcGVjaWZ5IHRoZW0gdXNpbmcgdGhlIHN5bnRheCBiZWxvdzoKCmBgYHtyfQoKam9pbmVkX2ZydWl0ID0gbGVmdF9qb2luKGZydWl0X2RhdGEsIGZydWl0X2RheXMsIGJ5ID0gYygiZnJ1aXQiID0gImZydWl0X3R5cGUiKSkKCmpvaW5lZF9mcnVpdAoKYGBgCgpJbiB0aGlzIG5ldyBkYXRhZnJhbWUsIHRoZSBjb3JyZWN0IHdlZWtkYXkgaXMgbm93IGxpc3RlZCBiZXNpZGUgdGhlIHJlbGV2YW50IGZydWl0IHR5cGUuCgojIyMgUGlwaW5nCgpBbm90aGVyIHVzZWZ1bCBmZWF0dXJlIG9mIHRoZSB0aWR5dmVyc2UgaXMgdGhhdCB5b3UgY2FuICdwaXBlJyBjb21tYW5kcyB0aHJvdWdoIGEgYnVuY2ggb2YgZnVuY3Rpb25zLCBtYWtpbmcgaXQgZWFzaWVyIHRvIGZvbGxvdyB0aGUgbG9naWNhbCBvcmRlciBvZiB0aGUgY29kZS4gVGhpcyBtZWFucyB0aGF0IHlvdSBjYW4gZG8gb25lIG9wZXJhdGlvbiwgYW5kIHBhc3MgdGhlIHJlc3VsdCB0byBhbm90aGVyIG9wZXJhdGlvbi4gVGhlIHByZXZpb3VzIGRhdGFmcmFtZSBpcyBwYXNzZWQgYXMgdGhlIGZpcnN0IGFyZ3VtZW50IG9mIHRoZSBuZXh0IGZ1bmN0aW9uIGJ5IHVzaW5nIHRoZSBwaXBlIGAlPiVgIGNvbW1hbmQuIEl0IHdvcmtzIGxpa2UgdGhpczoKCmBgYHtyfQpmcnVpdF9kYXRhICU+JSAKICBmaWx0ZXIoY29sb3VyICE9ICd5ZWxsb3cnKSAlPiUgIyByZW1vdmUgYW55IHllbGxvdyBjb2xvdXIgZnJ1aXQKICBncm91cF9ieShmcnVpdCkgJT4lICMgZ3JvdXAgdGhlIGZydWl0IGJ5IHR5cGUKICB0YWxseShhbW91bnQpICU+JSAjIGNvdW50IGVhY2ggZ3JvdXAKICBhcnJhbmdlKGRlc2MobikpICMgYXJyYW5nZSBpbiBkZXNjZW5kaW5nIG9yZGVyIG9mIHRoZSBjb3VudApgYGAKClRoYXQgY29kZSBibG9jaywgd3JpdHRlbiBpbiBwcm9zZTogInRha2UgZnJ1aXQgZGF0YSwgcmVtb3ZlIGFueSB5ZWxsb3cgY29sb3VyIGZydWl0LCBjb3VudCB0aGUgZnJ1aXRzIGJ5IHR5cGUgYW5kIGFtb3VudCwgYW5kIGFycmFuZ2UgaW4gZGVzY2VuZGluZyBvcmRlciBvZiB0aGUgdG90YWwiCgojIyBQbG90dGluZyB1c2luZyBnZ3Bsb3QoKQoKIVtTb3VyY2U6IGh0dHBzOi8vYWxsaXNvbmhvcnN0LmNvbS9yLXBhY2thZ2VzLWZ1bmN0aW9uc10oaW1hZ2VzLzM1MmM5MDVkLTdiZTMtNDgwOC05NTE0LTFmYWMzYjBmZTJmYy5wbmcpe2ZpZy1hbHQ9IkEgZ3JvdXAgb2YgZnV6enkgcm91bmQgbW9uc3RlcnMgd2l0aCBiaW5vY3VsYXJzLCBiYWNrcGFja3MgYW5kIGd1aWRlIGJvb2tzIGxvb2tpbmcgdXAgYSBncmFwaHMgZmx5aW5nIGFyb3VuZCB3aXRoIHdpbmdzIChsaWtlIGJpcmRlcnMsIGJ1dCB3aXRoIGV4cGxvcmF0b3J5IGRhdGEgdmlzdWFsaXphdGlvbnMpLiBTdHlsaXplZCB0ZXh0IHJlYWRzIOKAnGdncGxvdDI6IHZpc3VhbCBkYXRhIGV4cGxvcmF0aW9uLuKAnSJ9CgpUaGUgdGlkeXZlcnNlIGluY2x1ZGVzIGEgcGxvdHRpbmcgbGlicmFyeSBjYWxsZWQgYGdncGxvdDJgLiBBbG1vc3QgYWxsIG9mIHRoZSBwcmFjdGljYWwgcGFydHMgb2YgdGhpcyBjb3Vyc2Ugd2lsbCB1c2UgaXQsIHNvIGl0J3MgZ29vZCB0byBzdGFydCBwcmFjdGlzaW5nLiBEb24ndCB3b3JyeSBpZiB5b3UgZG9uJ3QgZ2V0IGl0IGF0IGZpcnN0IC0gd2UnbGwgY29tZSBiYWNrIHRvIHRoZSBiYXNpY3Mgb3ZlciB0aGUgbmV4dCBmZXcgd2Vla3MuCgpUbyB1c2UgaXQsIGZpcnN0IHR5cGUgdGhlIGZ1bmN0aW9uIGBnZ3Bsb3QoKWAgYW5kIHNwZWNpZnkgdGhlIGRhdGFzZXQgeW91IHdpc2ggdG8gZ3JhcGggdXNpbmcgYGRhdGEgPWAuIE5leHQsIGFkZCB3aGF0IGlzIGtub3duIGFzIGEgJ2dlb20nOiBhIGZ1bmN0aW9uIHdoaWNoIHRlbGxzIHRoZSBwYWNrYWdlIHRvIHJlcHJlc2VudCB0aGUgZGF0YSB1c2luZyBhIHBhcnRpY3VsYXIgZ2VvbWV0cmljIGZvcm0gKHN1Y2ggYXMgYSBiYXIsIG9yIGEgbGluZSkuIFRoZXNlIGZ1bmN0aW9ucyBiZWdpbiB3aXRoIHRoZSBzdGFuZGFyZCBmb3JtIGBnZW9tX2AuCgpXaXRoaW4gdGhpcyBnZW9tLCB5b3UnbGwgYWRkICdhZXN0aGV0aWNzJywgd2hpY2ggc3BlY2lmeSB0byB0aGUgcGFja2FnZSB3aGljaCBwYXJ0IG9mIHRoZSBkYXRhIG5lZWRzIHRvIGJlIG1hcHBlZCB0byB3aGljaCBwYXJ0aWN1bGFyIGVsZW1lbnQgb2YgdGhlIGdlb20uIFRoZSBtb3N0IGNvbW1vbiBvbmVzIGluY2x1ZGUgYHhgIGFuZCBgeWAgZm9yIHRoZSB4IGFuZCB5IGF4ZXMsIGBjb2xvcmAgb3IgYGZpbGxgIHRvIG1hcCBjb2xvcnMgaW4geW91ciBwbG90IHRvIHBhcnRpY3VsYXIgZGF0YS4KClNvbWUgZXhhbXBsZXMgdXNpbmcgdGhlIGZydWl0IGRhdGE6CgpCYXIgY2hhcnQgb2YgZGlmZmVyZW50IHR5cGVzIG9mIGZydWl0IChvbmUgZWFjaCBvZiBiYW5hbmFzIGFuZCBvcmFuZ2VzLCB0d28gdHlwZXMgb2YgYXBwbGUpCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBmcnVpdF9kYXRhKSArIGdlb21fY29sKGFlcyh4ID0gZnJ1aXQsIHkgPSBhbW91bnQpKQpgYGAKCkNvdW50aW5nIHRoZSB0b3RhbCBhbW91bnQgb2YgZnJ1aXQ6CgpgYGB7cn0KZ2dwbG90KGZydWl0X2RhdGEpICsgZ2VvbV9jb2woYWVzKHggPSBmcnVpdCwgeSA9IGFtb3VudCkpCmBgYAoKQ2hhcnRpbmcgYW1vdW50cyBhbmQgZnJ1aXQgY29sb3VyczoKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IGZydWl0X2RhdGEpICsgZ2VvbV9iYXIoYWVzKHggPSBmcnVpdCwgd2VpZ2h0ID0gYW1vdW50LCBmaWxsID0gY29sb3VyKSkgCmBgYAoKIyMgUmVhZGluZyBpbiBleHRlcm5hbCBkYXRhCgpNb3N0IG9mIHRoZSB0aW1lLCB5b3UnbGwgYmUgd29ya2luZyB3aXRoIGV4dGVybmFsIGRhdGEgc291cmNlcy4gVGhlc2UgbW9zdCBjb21tb25seSBjb21lIGluIHRoZSBmb3JtIG9mIGNvbW1hIHNlcGFyYXRlZCB2YWx1ZXMgKC5jc3YpIG9yIHRhYiBzZXBhcmF0ZWQgdmFsdWVzICgudHN2KS4gVGhlIHRpZHl2ZXJzZSBjb21tYW5kcyB0byByZWFkIHRoZXNlIGFyZSBgcmVhZF9jc3YoKWAgYW5kIGByZWFkX3RzdmAuIFlvdSBjYW4gYWxzbyB1c2UgYHJlYWRfZGVsaW0oKWAsIGFuZCBzcGVjaWZ5IHRoZSB0eXBlIG9mIGRlbGltaXRlZCB1c2luZyBgZGVsaW0gPSAnLCdgIG9yIGBkZWxpbSA9ICcvdGAuIFRoZSBwYXRoIHRvIHRoZSBmaWxlIGlzIGdpdmVuIGFzIGEgc3RyaW5nIHRvIHRoZSBhcmd1bWVudCBgZmlsZT1gLgoKYGBge3IsIGV2YWwgPSBGQUxTRX0KCmRmID0gcmVhZF9jc3YoZmlsZSA9ICd0b3BfbW92aWUuY3N2JykgIyBSZWFkIGEgLmNzdiBmaWxlIGFzIGEgbmV0d29yaywgc3BlY2lmeSB0aGUgcGF0aCB0byB0aGUgZmlsZSBoZXJlLgoKZGYKCmBgYAoKTm90aWNlIHRoYXQgZWFjaCBjb2x1bW4gaGFzIGEgZGF0YSB0eXBlIGJlc2lkZSBpdCwgZWl0aGVyIDxjaHI+IGZvciB0ZXh0IG9yIDxkYmw+IGZvciBudW1iZXJzLiBUaGlzIGlzIGltcG9ydGFudCBpZiB5b3Ugd2FudCB0byBzb3J0IG9yIHJ1biBjYWxjdWxhdGlvbnMgb24gdGhlIGRhdGEuCgpBZHZhbmNlZDogYHN0cl/CpWAKCiMjIEV4ZXJjaXNlcwoKTm93IGlzIGEgY2hhbmNlIHRvIHByYWN0aWNlIFIgc2tpbGxzIG9uIHlvdXIgb3duLgoKRmlyc3QsIGNyZWF0ZSBhIG5ldyBtYXJrZG93biBub3RlYm9vaywgZm9sbG93aW5nIHRoZSBpbnN0cnVjdGlvbnMgZnJvbSBsYXN0IHdlZWsuCgpOZXh0LCBjb21wbGV0ZSB0aGUgZm9sbG93aW5nIGV4ZXJjaXNlcy4gVHlwZSB0aGUgbmFtZSBvZiB0aGUgZXhlcmNpc2UsIGFuZCB0aGVuIGNyZWF0ZSBhIHNlcGFyYXRlIGNvZGUgY2VsbCBmb3IgZWFjaCBvbmUuCgojIyMjIEV4ZXJjaXNlIDA6IGxvYWQgdGhlIHRpZHl2ZXJzZSBsaWJyYXJ5CgpMb2FkIHRoZSB0aWR5dmVyc2UgbGlicmFyeSBpbnRvIHlvdXIgbWFya2Rvd24gZmlsZSAoZm9yIGFueSBtYXJrZG93biBmaWxlLCB5b3UgbmVlZCB0byBsb2FkIGFsbCB0aGUgcGFja2FnZXMgeW91IHVzZSB3aXRoaW4gaXQuIEl0IGRvZXNuJ3QgbWF0dGVyIGlmIHlvdSBoYXZlIGFscmVhZHkgbG9hZGVkIHRoZSBwYWNrYWdlcyBzZXBhcmF0ZWx5LgoKIyMjIyBFeGVyY2lzZSAxOiByZWFkIHRoZSBmaWxlIGB0b3BfbW92aWUuY3N2YCBpbnRvIFIuIEdpdmUgaXQgdGhlIG5hbWUgYGRmX21vdmllYC4KCiMjIyMgRXhlcmNpc2UgMjogQ3JlYXRlIGEgbmV3IHZlcnNpb24gb2YgYGRmX21vdmllYCwgY2FsbGVkIGBkZl9tb3ZpZV9jbGVhbmVkYCB3aGljaDoKCi0gICBPbmx5IGluY2x1ZGVzIHRoZSB5ZWFycyAyMDAwIHRvIDIwMjAuCgotICAgT25seSBjb250YWlucyB0aGUgYHllYXJgLCBgbW92aWVgLCBgZGlzdHJpYnV0b3JgIGFuZCBgdG90YWxfaW5fMjAyMl9kb2xsYXJzYCBjb2x1bW5zLgoKIyMjIyBFeGVyY2lzZSAzOiBzdW1tYXJpc2UgdGhlIGRhdGEuIFByaW50IHRoZSBmb2xsb3dpbmcgdW5kZXIgdGhlIGNlbGwgb3V0cHV0OgoKLSAgIEEgY291bnQgb2YgdGhlIG51bWJlciBvZiB0aXRsZXMgaW4gYGRmX21vdmllX2NsZWFuZWRgIHBlciBlYWNoIGRpc3RyaWJ1dG9yLgoKLSAgIEEgY291bnQgb2YgdGhlIHRvdGFsIGJveCBvZmZpY2UgdGFraW5ncyBmb3IgZWFjaCBkaXN0cmlidXRvci4KCiMjIyMgRXhlcmNpc2UgNTogU29ydCB0aGUgZGF0YToKClNvcnQgYnkgdGhpcyBsYXR0ZXIgYW1vdW50IGluIGRlc2NlbmRpbmcgb3JkZXIsIGFuZCBwcmludCB0aGlzIHJlc3VsdCB1bmRlciB0aGUgY2VsbC4KClNhdmUgYW5kIGtuaXQgdGhlIG1hcmtkb3duIGZpbGUsIHN1Ym1pdCB1bmRlciAnd2Vla2x5IHRhc2tzJyBmb3Igd2VlayAzLg==